﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using MapWindow.Components;
using MapWindow.Data;
using MapWindow.Data.IO;
using MapWindow.Drawing;
using MapWindow.Geometries;
using MapWindow.Main;
using Point=System.Drawing.Point;

namespace StandaloneTest
{
    public partial class Form1 : Form
    {
        private byte[] _values;
        private PyramidImage pim;
        private int _width;
        private int _height;
        private Bitmap _bmp;
        private FeatureSet _fs;
        public Form1()
        {
            InitializeComponent();
           
        }

        private void Open()
        {
            

        }

        private void CopyPolygon()
        {
            FeatureSet fs = new FeatureSet();
            fs.Open();
            map1.Layers.Add(CopyFeatures(fs));
        }

        /// <summary>
        /// Pretend that the 0 index column has the binary WKB representation of features.
        /// </summary>
        /// <param name="table"></param>
        private void ReadWKB(DataTable table)
        {
            
            List<Shape> shapes = new List<Shape>();
            foreach (DataRow row in table.Rows)
            {
                byte[] content = (byte[]) row[0];
                MemoryStream source = new MemoryStream(content);
                // Can read anything except a generic geometry collection with potentially mixed content
                Shape result = WkbFeatureReader.ReadShape(source);
                if(result.Range.FeatureType == FeatureTypes.Polygon)
                {
                    // Only add the shape if it is a polygon
                    shapes.Add(result);
                    // Maybe some attribute indexing code here if attributes are needed
                }
            }
            FeatureSet polygons = new FeatureSet(FeatureTypes.Polygon);
            polygons.IndexMode = true;
            // Adding in one swoop should reduce the amount of re-dimensioning of the arrays.
            polygons.AddShapes(shapes);
        }


        private IFeatureSet CopyFeatures(IFeatureSet fs)
        {
            int numRows = 10;
            for(int row = 0; row < numRows; row++)
            {
                
            }


            FeatureSet result = new FeatureSet(fs.FeatureType);
            result.IndexMode = true;
            List<Shape> shapes = new List<Shape>();
            for(int i = 0; i < fs.ShapeIndices.Count; i++)
            {
                shapes.Add(fs.GetShape(i, false));
            }
            result.AddShapes(shapes);
            //result.AddShape(shapes[1]);
            return result;
        }



        private void AddRange(Feature[] features)
        {
            FeatureSet fs = new FeatureSet();
            fs.Features.SuspendEvents();
            for (int i = 0; i < features.Length; i++ )
            {
                fs.Features.Add(features[i]);
            }
            fs.Features.ResumeEvents();
        }

        private void SomeBasicsForAllLayers()
        {
            // A layer combines data, symbology, and drawing functions.
            // Some things can be controlled directly with the layer:
            ILayer layer = map1.Layers[0];

            // Feature Layers only share some general symbology, but give
            // full access to the vector featrueset on the dataset.
            IFeatureLayer fl = layer as IFeatureLayer; 
          
            // Safe casting may produce a null value
            if(fl != null)
            {
                // The dataset at this stage is automatically an IFeatureSet.
                IFeatureSet fs = fl.DataSet;

                // Further Subtypes include Line, Point, and Polygon layers
                IPointLayer pointl = fl as IPointLayer;
                if(pointl != null)
                {
                    // point schemes control multiple categories of description with filter expressions for each category
                    IPointScheme pscheme = pointl.Symbology;
                    // A point symbolizers are a shortcut to Symbology.Categories[0].Symbolizer
                    IPointSymbolizer psymb = pointl.Symbolizer;
                }
                // The same works for Lines
                ILineLayer ll = fl as ILineLayer;
                if(ll != null)
                {
                    ILineScheme lscheme = ll.Symbology;
                    ILineSymbolizer ls = ll.Symbolizer;
                }
                // And Polygons
                IPolygonLayer pl = fl as IPolygonLayer;
                if(pl != null)
                {
                    IPolygonScheme pscheme = pl.Symbology;
                    IPolygonSymbolizer ps = pl.Symbolizer;
                }
                // You will not find label layers directly in the map layers collection.
                // Instead they belong directly to a feature layer.
                fl.LabelLayer.Symbology.Categories[0].Expression = "[" + fs.DataTable.Columns[0].ColumnName + "]";
            }
            // Raster Layers have an IRaster for the DataSet, instead of an IFeatureSet
            IRasterLayer rl = layer as IRasterLayer;
            if(rl != null)
            {
                // The IRaster interface allows easy access to the data values.
                IRaster r = rl.DataSet;
                // There is only one raster symbolizer and it controls the basic properties
                IRasterSymbolizer symbolizer = rl.Symbolizer;
                // The color scheme lists the color settings
                IColorScheme scheme = symbolizer.Scheme;
            }

            // Image layers work 
            IImageLayer il = layer as IImageLayer;
            if(il != null)
            {
                // Image data controls the data access for the colors at a pixel location,
                // or else provides direct access to a byte array representing the image.
                IImageData id = il.DataSet;

                // A bitmap retrieval method automatically scales the representation
                // for the specified geographic extent so that it works with the pixel
                // size of the specified client rectangle.
                Bitmap bmp = id.GetBitmap(map1.Extents, map1.ClientRectangle);

                // At the moment the symbolizer here is just a placeholder for potential future uses.
            }
        }




        
        private void CycleThroughVertices()
        {
            // The feature set class works directly with vector data
            FeatureSet fs = new FeatureSet();
            // Opening a shapefile from disk loads data in "Index" mode by default.
            fs.Open("filename.shp");

            // ShapeRanges can also be created from envelopes.
            ShapeRange bounds = new ShapeRange(map1.Extents);

            // The shapes rely on an array of double precision interleaved
            // [X1, Y1, X2, Y2, ... Xn, Yn] coordinates.
            double x1 = fs.Vertex[0];
            double y1 = fs.Vertex[1];

            // The shaperange indexes values based on the coordinate index,
            // not the position in the double array.
            // Do access the coordinate directly from the Vertex, multiply by 2.
            x1 = fs.ShapeIndices[2].StartIndex*2;
            y1 = fs.ShapeIndices[2].StartIndex*2 + 1;

            // You can use the startindex and count in order to cycle values manually,
            // but it can be confusing.  To make things simpler, the ShapeIndices support an 
            // enumeration that allows cycling though the shapes, parts and the vertices.
            foreach (ShapeRange shape in fs.ShapeIndices)
            {
                if(shape.Intersects(bounds))
                foreach (PartRange part in shape.Parts)
                {
                    foreach (Vertex vertex in part)
                    {
                        if(vertex.X > 0 && vertex.Y > 0)
                        {
                            // do something
                        }
                    }
                }
            }
        }

        // Example for the specific case of polygons
        private void SetPolygonColor(object sender, EventArgs e)
        {
            FeatureSet fs = new FeatureSet();
            fs.Open();
            IFeatureLayer fl = map1.Layers.Add(fs);
            fl.SetShapeSymbolizer(2, new PolygonSymbolizer(Color.Blue));
        }

        void map1_MouseDown(object sender, MouseEventArgs e)
        {
            //Coordinate c = map1.PixelToProj(e.Location);
            //List<IFeature> res = new List<IFeature>();
            //IFeatureSet fs = map1.Layers[0].DataSet as IFeatureSet;

            //if(fs != null)
            //{
            //    res = fs.Select(new Envelope(c));
            //}
            //bool stop = true;
        }


        //Extent ext = new Extent();
            //ext.XMin = 10;
            //ext.XMax = 100;
            //ext.YMin = 15;
            //ext.YMax = 150;
            //ShapeRange sr = new ShapeRange(ext);
            //foreach (PartRange part in sr.Parts)
            //{
            //    foreach (Vertex vertex in part)
            //    {
            //        double x = vertex.X;
            //        double y = vertex.Y;
            //        bool stop = true;
            //    }
            //    foreach (Segment segment in part.Segments)
            //    {
            //        Vertex v1 = segment.P1;
            //        Vertex v2 = segment.P2;
            //        bool stop = true;
            //    }
            //}
            


            //OpenFileDialog ofd = new OpenFileDialog();
            //if(ofd.ShowDialog() != DialogResult.OK) return;
            //Image img = Image.FromFile(ofd.FileName);
            //_bmp = new Bitmap(img.Width, img.Height, PixelFormat.Format32bppArgb);
            //Graphics g = Graphics.FromImage(_bmp);
            //g.DrawImage(img, 0, 0);
            //g.Dispose();
            //CreateGraphics().DrawImage(_bmp, 0, 0);
           
            
           
        

        private void button2_Click(object sender, EventArgs e)
        {
            map1.FunctionMode = FunctionModes.Zoom;
            map1.AddLayer();

            //MwPng mp = new MwPng();
            //mp.Write(_bmp, "C:\\testImage.mw.png");


            //_bmp.Save("C:\\testimage.mw2.png");
            //pim = new PyramidImage();
            //pim.Filename = "C:\\testImage.mwi";
            //pim.CreateHeaders(_height, _width, new double[]{0, 1, 0, 0, 0, 1});
            //pim.WriteWindow(_values, 0, 0, _height, _width, 0);
            

        }

        private void button4_Click(object sender, EventArgs e)
        {
           
            int scale =(int)numericUpDown1.Value;
            PyramidImageHeader ph = pim.Header.ImageHeaders[scale];
            Rectangle bnds = new Rectangle(0, 0, ph.NumColumns, ph.NumRows);
            byte[] data = pim.ReadWindow(0, 0, ph.NumRows, ph.NumColumns, scale);
            Bitmap bmp = new Bitmap(ph.NumColumns, ph.NumRows);
            BitmapData bData = bmp.LockBits(bnds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            Marshal.Copy(data, 0, bData.Scan0, data.Length);
            bmp.UnlockBits(bData);
            Graphics g = CreateGraphics();
            g.FillRectangle(Brushes.Gray, 0, 0, 1000, 1000);
            g.DrawImageUnscaled(bmp, 0, 0);
            g.Dispose();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            pim.CreatePyramids(mwStatusStrip1);
            pim.WriteHeader(pim.Filename);
        }

        private void button5_Click(object sender, EventArgs e)
        {
            pim = new PyramidImage();
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "MapWindow Images (*.mwi)|*.mwi";
            if (ofd.ShowDialog() != DialogResult.OK) return;
            pim.Filename = ofd.FileName;
            pim.ReadHeader(ofd.FileName);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //Graphics g = CreateGraphics();
            //g.FillEllipse(Brushes.Blue, new Rectangle(100, 100, 400, 400));
            //g.DrawEllipse(Pens.Black, new Rectangle(100, 100, 400, 400));
            //Point c = new Point(300, 300);
            //for(int i = 0; i < 36; i++)
            //{
            //    Point rx = new Point(c.X + 200 * (int)Math.Cos(Math.PI * i/(double)36), c.Y + 200 * (int)Math.Cos(Math.PI * i/(double)36));
            //    Rectangle r = new Rectangle(rx.X - 5, rx.Y - 5, 10, 10);
            //    g.FillRectangle(Brushes.Red, r);
            //    g.DrawRectangle(Pens.Black, r);
            //}
            //g.Dispose();
        }



        private void IndexedWKB(DataTable source)
        {
            // Assume this DataTable has WKB in column[0] and the rest of the columns are attributes.
            FeatureSetPack result = new FeatureSetPack();
            foreach (DataRow row in source.Rows)
            {
                byte[] data = (byte[])row[0];
                MemoryStream ms = new MemoryStream(data);
                WkbFeatureReader.ReadFeature(ms, result);
            }
            // convert lists of arrays into a single vertex array for each shape type.
            result.StopEditing(); 
            // Make sure all the same columns exist in the same order
            result.Polygons.CopyTableSchema(source);
            // Assume that all the features happend to be polygons
            foreach (DataRow row in source.Rows)
            {
                // Create a new row
                DataRow dest = result.Polygons.DataTable.NewRow();
                // 
                dest.ItemArray = row.ItemArray;
                
            }
        }

        private void button6_Click(object sender, EventArgs e)
        {
            //Graphics g = CreateGraphics();
            //Point c = new Point(300, 300);
            //Point[] shell = new Point[36];
            //Point[] hole = new Point[36];
            //for (int i = 0; i < 36; i++)
            //{
            //    shell[i] = new Point(c.X + (int)(200 * Math.Cos(Math.PI * i / (double)18)), c.Y + (int)(200 * Math.Sin(Math.PI * i / (double)18)));
            //    hole[i] = new Point(c.X + (int)(100 * Math.Cos(Math.PI * (35-i) / (double)18)), c.Y + (int)(100 * Math.Sin(Math.PI * (35-i) / (double)18)));
                
            //}
            //GraphicsPath gp = new GraphicsPath();
            //gp.FillMode = FillMode.Winding;
            //gp.AddPolygon(shell);
            //gp.AddPolygon(hole);
            
            //g.FillPath(Brushes.Blue, gp);
            //g.DrawPath(Pens.Black, gp);

            //for (int i = 0; i < 36; i++ )
            //{
            //    Rectangle r = new Rectangle(shell[i].X - 5, shell[i].Y - 5, 10, 10);
            //    g.FillRectangle(Brushes.Red, r);
            //    g.DrawRectangle(Pens.Black, r);

            //    Rectangle r2 = new Rectangle(hole[i].X - 5, hole[i].Y - 5, 10, 10);
            //    g.FillRectangle(Brushes.Red, r2);
            //    g.DrawRectangle(Pens.Black, r2);
            //}


            //    gp.Dispose();
            //g.Dispose();
        }

        /// <summary>
        /// Testing for errors in X, Y coordinate positioning by saving using the 
        /// Net Topology Suite version, while opening using the WkbFeatureReader.
        /// </summary>
        private void TestBinary(object sender, EventArgs e)
        {
            
            // Dimension a new featureset
            FeatureSet fs = new FeatureSet();
            // Open the featureset using standard shapefile format
            fs.Open();

            // The output featureset to be created from wkb
            FeatureSet result = new FeatureSet(fs.FeatureType);


            // Store the WKB representation in a list of arrays, each shape has one array.
            List<byte[]> binaryShapes = new List<byte[]>();
            
            // This forces the creation of features, and uses the old WKB converter
            // which was the NTS implementation of the standard OGC WKB.
            WKBWriter writer = new WKBWriter(ByteOrder.LittleEndian);
            foreach (IFeature feature in fs.Features)
            {
                binaryShapes.Add(writer.Write(Geometry.FromBasicGeometry(feature.BasicGeometry)));
            }

            // Start by setting up a list of shapes
            List<Shape> shapes = new List<Shape>();

            // Loop through the binary arrays
            foreach (byte[] rawBytes in binaryShapes)
            {
                // read each 
                MemoryStream ms = new MemoryStream(rawBytes);
                shapes.Add(WkbFeatureReader.ReadShape(ms));
            }

            // As of the most recent source commit, this also works if it is false.
            result.IndexMode = true; 
            // Adds the shapes to the result in one pass, so that there is less array re-dimensioning
            result.AddShapes(shapes);
            // opens the result as a new layer on the map
            map1.Layers.Add(result);
        }


        private void TestLargeMultiPoint(object sender, EventArgs e)
        {
            FeatureSet fs = new FeatureSet(FeatureTypes.MultiPoint);
            Random rnd = new Random();
            fs.DataTable.Columns.Add("Alpha", typeof(int));
            int numPoints = 360000;
            ProgressMeter pm = new ProgressMeter(mwStatusStrip1, "Creation", numPoints);
            for(int i = 0; i < numPoints; i++)
            {
                Coordinate[] coords = new Coordinate[2];
                coords[0] = new Coordinate(rnd.NextDouble(), rnd.NextDouble());
                coords[1] = new Coordinate(rnd.NextDouble(), rnd.NextDouble());
                fs.Features.Add(new MultiPoint(coords));
                pm.CurrentValue = i;
            }
            fs.ProgressHandler = mwStatusStrip1;
            fs.SaveAs("C:\\testmulti.shp", true);
            fs = new FeatureSet();
            fs.ProgressHandler = mwStatusStrip1;
            fs.Open("C:\\testmulti.shp");
            map1.Layers.Add(fs);

        }

       
      
      
    }
}
